package com.smedi.ismedi.cronjob.core.domain.service.impl;

import cn.hutool.json.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.smedi.ismedi.cronjob.core.domain.aggregatemodel.JobRun;
import com.smedi.ismedi.cronjob.core.domain.repository.JobRunRepository;
import com.smedi.ismedi.cronjob.core.infrastructure.constant.ConstantField;
import com.smedi.ismedi.cronjob.core.infrastructure.util.HttpUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.CharSet;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Set;


@Slf4j
@Component
public class JobImpl implements Job {
    @Autowired
    JobRunRepository cronjobRunRepository;

    @Autowired
    HttpUtil httpUtil;

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private LoadBalancerClient loadBalancerClient;

    @SneakyThrows
    @Override
    public void execute(JobExecutionContext executorContext){
        JobDataMap map = executorContext.getMergedJobDataMap();

        LocalDateTime startTime = LocalDateTime.now();

        JobRun jobRun = new JobRun();
        StringBuilder stringBuilder = new StringBuilder();

        log.info("Running Job name : {} ", map.getString("name"));
        log.info("Running Job description : {}", map.getString("jobDescription"));
        log.info("Running Job group: {} ", map.getString("group"));
        log.info(String.format("Running Job cron : %s", map.getString("cronExpression")));
        log.info("Running Job URL: {} ", map.getString("jobUrl"));

        stringBuilder.append("Job name:");
        stringBuilder.append(map.getString("name"));
        stringBuilder.append(", description:");
        stringBuilder.append(map.getString("jobDescription"));
        stringBuilder.append(", group:");
        stringBuilder.append(map.getString("group"));
        stringBuilder.append(", cron:");
        stringBuilder.append(map.getString("cronExpression"));
        stringBuilder.append(", URL:");
        stringBuilder.append(map.getString("jobUrl"));
        stringBuilder.append(", parameter:");
        stringBuilder.append(map.getString("parameter"));

        jobRun.setJobId(map.getLong("id"));
        jobRun.setStatus("running");
        jobRun.setStartedTime(startTime);
        jobRun = cronjobRunRepository.doInsert(jobRun);
        String url = map.getString("jobUrl");
        String parameter = map.getString("parameter");
        String type = map.getString("type");
        String serviceName = map.getString("serviceName");

        String result = null;
        if (url != null && !url.isEmpty() && (StringUtils.isBlank(type)  || StringUtils.isBlank(serviceName))) {
            try {
                result = httpUtil.post(url, parameter);
                jobRun.setStatus("success");
            } catch (Exception e) {
                e.printStackTrace();
                stringBuilder.append(e.getMessage());
                jobRun.setStatus("fail");
            }
        }
        if(StringUtils.isNotBlank(type) && StringUtils.isNotBlank(serviceName) && StringUtils.isNotBlank(url)){
            if(type.equals(ConstantField.GET)){
                try {
                    StringBuilder address = new StringBuilder();
                    ServiceInstance instance = loadBalancerClient.choose(serviceName);
                    address.append(instance.getUri());
                    if(url.startsWith("/")){
                        address.append(url);
                    }else {
                        address.append("/").append(url);
                    }
                    if(parameter != null && !parameter.isEmpty()){
                        address.append("?");
                        Map<String,Object> params = JSONObject.parseObject(parameter,Map.class);
                        Set<String> keySet = map.keySet();
                        for(String key : keySet){
                            address.append(key).append("={").append(key).append("}&");
                        }
                        result = restTemplate.getForObject(address.toString(),String.class,params);
                    }else {
                        result = restTemplate.getForObject(address.toString(),String.class);
                    }
                    jobRun.setStatus("success");
                }catch (Exception e){
                    log.error(e.getMessage());
                    stringBuilder.append(e.getMessage());
                    jobRun.setStatus("fail");
                }
            }
            if (type.equals(ConstantField.POST)){
                try {
                    StringBuilder address = new StringBuilder();
                    ServiceInstance instance = loadBalancerClient.choose(serviceName);
                    address.append(instance.getUri());
                    if(url.startsWith("/")){
                        address.append(url);
                    }else {
                        address.append("/").append(url);
                    }

                    if(parameter != null && !parameter.isEmpty()){
                        Map<String,Object> params = JSONObject.parseObject(parameter,Map.class);
                        result = restTemplate.postForObject(address.toString(),params,String.class);
                    }else {
                        result = restTemplate.postForObject(address.toString(),null,String.class);
                    }
                    jobRun.setStatus("success");
                }catch (Exception e){
                    log.error(e.getMessage());
                    stringBuilder.append(e.getMessage());
                    jobRun.setStatus("fail");
                }
            }
        }

        jobRun.setLog(stringBuilder.toString());
        LocalDateTime endTime = LocalDateTime.now();
        jobRun.setEndedTime(endTime);
        if (result != null && result.length() > 3000) {
            result = result.substring(0, 3000);
        }
        jobRun.setResult(result);
        cronjobRunRepository.doUpdate(jobRun);

        log.info(">>>>>>>>>>>>> Running Job has been completed , cost time : {}ms\n ", (endTime.getSecond() - startTime.getSecond()));
    }
}
